package cn.itcast.common.excel;

import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

/**
 * Excel其他功能增强
 */
public class ExcelOtherStrongUtils {
    /**
     * Excel增强冻结表头
     * 指定workbook下某sheet的冻结
     * 冻结方法：
     * sheet.createFreezePane(2, 3);
     * 参数解释：
     * 参数一右边区域可见的左边列数（左右移动） 参数二下面区域可见的首行
     * 冻结方法：
     * 冻结第一行  sheet1.createFreezePane( 0, 1, 0, 1 );
     * 参数解释：
     * 前两个参数是你要用来拆分的列数和行数。后两个参数是下面窗口的可见象限，其中第三个参数是右边区域可见的左边列数，第四个参数是下面区域可见的首行
     * @param rowSplit 右边区域可见的左边列数（左右移动
     * @param colSplit 下面区域可见的首行
     */
    public static void freezeTitle(Sheet sheet, int rowSplit, int colSplit) {
        //int rowsCount = sheet.getPhysicalNumberOfRows();
        // 参数一右边区域可见的左边列数（左右移动） 参数二下面区域可见的首行
        sheet.createFreezePane(colSplit, rowSplit);
        // sheet.createFreezePane(0, rowsCount - 1);
        // 冻结第一行  sheet1.createFreezePane( 0, 1, 0, 1 );
        // 冻结第一列 sheet2.createFreezePane( 1, 0, 1, 0 );
        // 前两个参数是你要用来拆分的列数和行数。后两个参数是下面窗口的可见象限，其中第三个参数是右边区域可见的左边列数，第四个参数是下面区域可见的首行
        // sheet1.createFreezePane( 3, 2, 3, 2 );
    }

    /**
     * Excel全局同步表头增强冻结
     * 指定workbook下某sheet的冻结
     * 冻结方法：
     * sheet.createFreezePane(2, 3);
     * 参数解释：
     * 参数一右边区域可见的左边列数（左右移动） 参数二下面区域可见的首行
     * 冻结方法：
     * 冻结第一行  sheet1.createFreezePane( 0, 1, 0, 1 );
     * 参数解释：
     * 前两个参数是你要用来拆分的列数和行数。后两个参数是下面窗口的可见象限，其中第三个参数是右边区域可见的左边列数，第四个参数是下面区域可见的首行
     * @param rowSplit 右边区域可见的左边列数（左右移动
     * @param colSplit 下面区域可见的首行
     */
    public static void freezeGlobalTitle(Workbook workbook, int rowSplit, int colSplit) {
        int sheetNum = workbook.getNumberOfSheets() ;
        for(int i = 0; i < sheetNum; i++){
            // 参数一右边区域可见的左边列数（左右移动） 参数二下面区域可见的首行
            workbook.getSheetAt(i).createFreezePane(colSplit, rowSplit);
        }
        // sheet.createFreezePane(0, rowsCount - 1);
        // 冻结第一行  sheet1.createFreezePane( 0, 1, 0, 1 );
        // 冻结第一列 sheet2.createFreezePane( 1, 0, 1, 0 );
        // 前两个参数是你要用来拆分的列数和行数。后两个参数是下面窗口的可见象限，其中第三个参数是右边区域可见的左边列数，第四个参数是下面区域可见的首行
        // sheet1.createFreezePane( 3, 2, 3, 2 );
    }

    /**
     * Excel功能增强写入列头下分隔符  会清除指定行的数据
     *  该功能摸到注解无用，定制化可以考虑使用
     *  @param workbook POI 操作Excel对象
     *  @param sheet 指定页签
     *  @param rowsCount 在第几行写入分割符号 注意：该行的单元格个数需要保持最大化,即不包括合并单元格
     */
    public static void writeDelimiter(Workbook workbook ,Sheet sheet, int rowsCount) {
        // 行数
        // int rowsCount = sheet.getPhysicalNumberOfRows();
        // 列数
        int colsCount = sheet.getRow(rowsCount).getPhysicalNumberOfCells();// 注意：该行的单元格个数需要保持最大化,即不包括合并单元格
        Cell cell;
        CellStyle cs = workbook.createCellStyle();
        Row row = sheet.createRow(rowsCount);
        for (int c = 0; c < colsCount; c++) {
            cell = row.createCell(c);
            cs.setBorderTop(BorderStyle.MEDIUM_DASHED);
            cs.setFillForegroundColor(HSSFColor.HSSFColorPredefined.ROSE.getIndex());
            cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            cell.setCellStyle(cs);
        }
    }

    /**
     * Excel功能增强全局写入列头下分隔符  会清除指定行的数据
     *  该功能摸到注解无用，定制化可以考虑使用
     *  @param workbook POI 操作Excel对象
     *  @param rowsCount 在第几行写入分割符号 注意：该行的单元格个数需要保持最大化,即不包括合并单元格
     */
    public static void writeGlobalDelimiter(Workbook workbook, int rowsCount) {
        int sheetNum = workbook.getNumberOfSheets() ;
        for (int i = 0; i < sheetNum; i++) {
            // 行数
            // int rowsCount = sheet.getPhysicalNumberOfRows();
            // 列数
            int colsCount = workbook.getSheetAt(i).getRow(rowsCount).getPhysicalNumberOfCells();// 注意：该行的单元格个数需要保持最大化,即不包括合并单元格
            Cell cell;
            CellStyle cs = workbook.createCellStyle();
            Row row = workbook.getSheetAt(i).createRow(rowsCount);
            for (int c = 0; c < colsCount; c++) {
                cell = row.createCell(c);
                cs.setBorderTop(BorderStyle.MEDIUM_DASHED);
                cs.setFillForegroundColor(HSSFColor.HSSFColorPredefined.ROSE.getIndex());
                cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                cell.setCellStyle(cs);
            }
        }
    }

    /**
     * Excel功能增强自动合并行
     * @param sheet 指定某sheet操作
     * @param startRowNum
     *  传入固定列头值即可
     *  指定从某行开始向下扫描合并,startRowsCount该值为减掉的列头，表头或警告头的行数，因为这些暂不需要合并
     *  或者可以将列头，表头或警告头需要合并的地方初始时写入相同的数据统一自动合并
     */
    public static void mergeRows(Sheet sheet, int startRowNum) {
        // Excel单元格总行数
        int rowsCount = sheet.getPhysicalNumberOfRows();;
        // 列数,最后一行数据的列数也为最大列数
        int colsCount = sheet.getRow(rowsCount-1).getPhysicalNumberOfCells();
        Row row1 = null;
        Row row2 = null;

        Cell cell1 = null;
        Cell cell2 = null;
        int rowSpan = 0;
        for (int c = 0; c < colsCount; c++) {
            rowSpan = 0;
            // 特殊表头情况（除列头，表头或警告头使用重复数据填充）需要减掉列头，表头或警告头占用的行数
            for(int r = startRowNum; r < rowsCount; r++){
                row1 = sheet.getRow(r);
                row2 = sheet.getRow(r+1);
                cell1 = row1.getCell(c);

                if (cell1 == null) {// 如果当前单元格是空的，跳过，继续下一行的单元格查找
                    if (r == rowsCount - 1) {
                        break;
                    } else {
                        continue;
                    }
                }

                if (row2 == null) {// 说明已经到最后一行了
                    if (rowSpan >= 1) {// 判断rowSpan是否大于等于1，大于1就要合并了
                        // 合并行中连续相同的值的单元格
                        sheet.addMergedRegion(new CellRangeAddress(r - rowSpan, r, c, c));
                        break;
                    }
                }else{
                    cell2 = row2.getCell(c);
                }

                if (cell1 != null && cell2 != null) {
                    if(cell1.getCellTypeEnum().equals(cell2.getCellTypeEnum())){ // 数据类型格式相同  进入合并
                        boolean flag = false ;
                        if(cell1.getCellTypeEnum().equals(CellType.NUMERIC)) {
                            if (cell1.getNumericCellValue() == cell2.getNumericCellValue()) {
                                flag = true ;
                            }
                        }

                        if(cell1.getCellTypeEnum().equals(CellType.STRING)) {
                            if (cell1.getStringCellValue().equals(cell2.getStringCellValue())) {
                                flag = true ;
                            }
                        }

                        if(cell1.getCellTypeEnum().equals(CellType.BOOLEAN)) {
                            if (cell1.getBooleanCellValue() == cell2.getBooleanCellValue()) {
                                flag = true ;
                            }
                        }

                        if(cell1.getCellTypeEnum().equals(CellType.BLANK)) {
                            flag = true ;
                        }

                        // 如果当前单元格和下一个单元格内容相同，那么colSpan加1
                        if (flag) {
                            rowSpan++;
                        } else {
                            // 如果当前单元格和下一个不等，那么判断colSpan是否大于等于1
                            if (rowSpan >= 1) {
                                // 合并行中连续相同的值的单元格
                                sheet.addMergedRegion(new CellRangeAddress(r - rowSpan, r, c, c));
                                // 合并后重置colSpan
                                rowSpan = 0;
                                continue;
                            }
                        }
                    }else {
                        // 如果当前单元格和下一个不等，那么判断colSpan是否大于等于1
                        if (rowSpan >= 1) {
                            // 合并行中连续相同的值的单元格
                            sheet.addMergedRegion(new CellRangeAddress(r - rowSpan, r, c, c));
                            // 合并后重置colSpan
                            rowSpan = 0;
                            continue;
                        }
                    }
                }
            }
        }
    }

    /**
     * Excel全局Sheet功能增强自动合并行
     * @param workbook Excel的workbook操作
     * @param startRowNum
     *  传入固定列头值即可
     *  指定从某行开始向下扫描合并,startRowsCount该值为减掉的列头，表头或警告头的行数，因为这些暂不需要合并
     *  或者可以将列头，表头或警告头需要合并的地方初始时写入相同的数据统一自动合并
     */
    public static void mergeGlobalRows(Workbook workbook, int startRowNum) {
        int sheetNum = workbook.getNumberOfSheets() ;
        for(int i = 0; i < sheetNum; i++){
            Sheet sheet = workbook.getSheetAt(i) ;
            // Excel单元格总行数
            int rowsCount = sheet.getPhysicalNumberOfRows();;
            // 列数,最后一行数据的列数也为最大列数
            int colsCount = sheet.getRow(rowsCount-1).getPhysicalNumberOfCells();
            Row row1 = null;
            Row row2 = null;

            Cell cell1 = null;
            Cell cell2 = null;
            int rowSpan = 0;
            for (int c = 0; c < colsCount; c++) {
                rowSpan = 0;
                // 特殊表头情况（除列头，表头或警告头使用重复数据填充）需要减掉列头，表头或警告头占用的行数
                for(int r = startRowNum; r < rowsCount; r++){
                    row1 = sheet.getRow(r);
                    row2 = sheet.getRow(r+1);
                    cell1 = row1.getCell(c);

                    if (cell1 == null) {// 如果当前单元格是空的，跳过，继续下一行的单元格查找
                        if (r == rowsCount - 1) {
                            break;
                        } else {
                            continue;
                        }
                    }

                    if (row2 == null) {// 说明已经到最后一行了
                        if (rowSpan >= 1) {// 判断rowSpan是否大于等于1，大于1就要合并了
                            // 合并行中连续相同的值的单元格
                            sheet.addMergedRegion(new CellRangeAddress(r - rowSpan, r, c, c));
                            break;
                        }
                    }else{
                        cell2 = row2.getCell(c);
                    }

                    if (cell1 != null && cell2 != null) {
                        if(cell1.getCellTypeEnum().equals(cell2.getCellTypeEnum())){ // 数据类型格式相同  进入合并
                            boolean flag = false ;
                            if(cell1.getCellTypeEnum().equals(CellType.NUMERIC)) {
                                if (cell1.getNumericCellValue() == cell2.getNumericCellValue()) {
                                    flag = true ;
                                }
                            }

                            if(cell1.getCellTypeEnum().equals(CellType.STRING)) {
                                if (cell1.getStringCellValue().equals(cell2.getStringCellValue())) {
                                    flag = true ;
                                }
                            }

                            if(cell1.getCellTypeEnum().equals(CellType.BOOLEAN)) {
                                if (cell1.getBooleanCellValue() == cell2.getBooleanCellValue()) {
                                    flag = true ;
                                }
                            }

                            if(cell1.getCellTypeEnum().equals(CellType.BLANK)) {
                                flag = true ;
                            }

                            // 如果当前单元格和下一个单元格内容相同，那么colSpan加1
                            if (flag) {
                                rowSpan++;
                            } else {
                                // 如果当前单元格和下一个不等，那么判断colSpan是否大于等于1
                                if (rowSpan >= 1) {
                                    // 合并行中连续相同的值的单元格
                                    sheet.addMergedRegion(new CellRangeAddress(r - rowSpan, r, c, c));
                                    // 合并后重置colSpan
                                    rowSpan = 0;
                                    continue;
                                }
                            }
                        }else {
                            // 如果当前单元格和下一个不等，那么判断colSpan是否大于等于1
                            if (rowSpan >= 1) {
                                // 合并行中连续相同的值的单元格
                                sheet.addMergedRegion(new CellRangeAddress(r - rowSpan, r, c, c));
                                // 合并后重置colSpan
                                rowSpan = 0;
                                continue;
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Excel功能增强自动合并列
     * @param sheet 指定某sheet操作
     * @param startRowNum 起始行位置，如果起始行，如果列头，表头或警告头使用重复数据填充，则该值可为0，否则若已经合并则跳过指定数目行
     */
    public static void mergeColumns(Sheet sheet, int startRowNum) {
        // 总行数
        int rowsCount = sheet.getPhysicalNumberOfRows();
        // 总列数
        int colsCount = sheet.getRow(rowsCount-1).getPhysicalNumberOfCells();

        Row row = null;
        Cell cell1 = null;
        Cell cell2 = null;

        int colSpan = 0;
        for (int r = startRowNum; r < rowsCount; r++) {
            row = sheet.getRow(r);
            // 重置
            colSpan = 0;
            row = sheet.getRow(r);
            for (int c = 0; c < colsCount; c++) {
                cell1 = row.getCell(c);
                cell2 = row.getCell(c + 1);
                if (cell1 == null) {// 如果当前单元格是空的，跳过，继续当前行的后一个单元格查找
                    if (c == colsCount - 1) {
                        break;
                    } else {
                        continue;
                    }
                }
                if (cell2 == null) {// 说明当前行已经到最后一个单元格了
                    if (colSpan >= 1) {// 判断colSpan是否大于等于1，大于1就要合并了
                        // 合并行中连续相同的值的单元格
                        sheet.addMergedRegion(new CellRangeAddress(r, r, c - colSpan, c));
                        break;
                    }
                }

                if (cell1 != null && cell2 != null) {
                    if(cell1.getCellTypeEnum().equals(cell2.getCellTypeEnum())){ // 数据类型格式相同  进入合并
                        boolean flag = false ;
                        if(cell1.getCellTypeEnum().equals(CellType.NUMERIC)) {
                            if (cell1.getNumericCellValue() == cell2.getNumericCellValue()) {
                                flag = true ;
                            }
                        }

                        if(cell1.getCellTypeEnum().equals(CellType.STRING)) {
                            if (cell1.getStringCellValue().equals(cell2.getStringCellValue())) {
                                flag = true ;
                            }
                        }

                        if(cell1.getCellTypeEnum().equals(CellType.BOOLEAN)) {
                            if (cell1.getBooleanCellValue() == cell2.getBooleanCellValue()) {
                                flag = true ;
                            }
                        }

                        if(cell1.getCellTypeEnum().equals(CellType.BLANK)) {
                            flag = true ;
                        }

                        // 如果当前单元格和下一个单元格内容相同，那么colSpan加1
                        if (flag) {
                            colSpan++;
                        } else {
                            // 如果当前单元格和下一个不等，那么判断colSpan是否大于等于1
                            if (colSpan >= 1) {
                                // 合并行中连续相同的值的单元格
                                sheet.addMergedRegion(new CellRangeAddress(r, r, c - colSpan, c));
                                // 合并后重置colSpan
                                colSpan = 0;
                                continue;
                            }
                        }
                    }else {
                        // 如果当前单元格和下一个不等，那么判断colSpan是否大于等于1
                        if (colSpan >= 1) {
                            // 合并行中连续相同的值的单元格
                            sheet.addMergedRegion(new CellRangeAddress(r, r, c - colSpan, c));
                            // 合并后重置colSpan
                            colSpan = 0;
                            continue;
                        }
                    }
                }
            }
        }
    }

    /**
     * Excel全局sheet功能增强自动合并列
     * @param workbook Excel操作workbook
     * @param startRowNum 起始行位置，如果起始行，如果列头，表头或警告头使用重复数据填充，则该值可为0，否则若已经合并则跳过指定数目行
     */
    public static void mergeGlobalColumns(Workbook workbook, int startRowNum) {
        int sheetNum = workbook.getNumberOfSheets() ;
        for(int i = 0 ; i < sheetNum; i++){
            // 总行数
            int rowsCount = workbook.getSheetAt(i).getPhysicalNumberOfRows();
            // 总列数
            int colsCount = workbook.getSheetAt(i).getRow(rowsCount-1).getPhysicalNumberOfCells();

            Row row = null;
            Cell cell1 = null;
            Cell cell2 = null;

            int colSpan = 0;
            for (int r = startRowNum; r < rowsCount; r++) {
                row = workbook.getSheetAt(i).getRow(r);
                // 重置
                colSpan = 0;
                row = workbook.getSheetAt(i).getRow(r);
                for (int c = 0; c < colsCount; c++) {
                    cell1 = row.getCell(c);
                    cell2 = row.getCell(c + 1);
                    if (cell1 == null) {// 如果当前单元格是空的，跳过，继续当前行的后一个单元格查找
                        if (c == colsCount - 1) {
                            break;
                        } else {
                            continue;
                        }
                    }
                    if (cell2 == null) {// 说明当前行已经到最后一个单元格了
                        if (colSpan >= 1) {// 判断colSpan是否大于等于1，大于1就要合并了
                            // 合并行中连续相同的值的单元格
                            workbook.getSheetAt(i).addMergedRegion(new CellRangeAddress(r, r, c - colSpan, c));
                            break;
                        }
                    }

                    if (cell1 != null && cell2 != null) {
                        if(cell1.getCellTypeEnum().equals(cell2.getCellTypeEnum())){ // 数据类型格式相同  进入合并
                            boolean flag = false ;
                            if(cell1.getCellTypeEnum().equals(CellType.NUMERIC)) {
                                if (cell1.getNumericCellValue() == cell2.getNumericCellValue()) {
                                    flag = true ;
                                }
                            }

                            if(cell1.getCellTypeEnum().equals(CellType.STRING)) {
                                if (cell1.getStringCellValue().equals(cell2.getStringCellValue())) {
                                    flag = true ;
                                }
                            }

                            if(cell1.getCellTypeEnum().equals(CellType.BOOLEAN)) {
                                if (cell1.getBooleanCellValue() == cell2.getBooleanCellValue()) {
                                    flag = true ;
                                }
                            }

                            if(cell1.getCellTypeEnum().equals(CellType.BLANK)) {
                                flag = true ;
                            }

                            // 如果当前单元格和下一个单元格内容相同，那么colSpan加1
                            if (flag) {
                                colSpan++;
                            } else {
                                // 如果当前单元格和下一个不等，那么判断colSpan是否大于等于1
                                if (colSpan >= 1) {
                                    // 合并行中连续相同的值的单元格
                                    workbook.getSheetAt(i).addMergedRegion(new CellRangeAddress(r, r, c - colSpan, c));
                                    // 合并后重置colSpan
                                    colSpan = 0;
                                    continue;
                                }
                            }
                        }else {
                            // 如果当前单元格和下一个不等，那么判断colSpan是否大于等于1
                            if (colSpan >= 1) {
                                // 合并行中连续相同的值的单元格
                                workbook.getSheetAt(i).addMergedRegion(new CellRangeAddress(r, r, c - colSpan, c));
                                // 合并后重置colSpan
                                colSpan = 0;
                                continue;
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 判断指定的单元格是否是合并单元格
     * @param sheet
     * @param row 行下标
     * @param column 列下标
     * @return
     */
    public static boolean isMergedRegion(Sheet sheet, int row ,int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if(row >= firstRow && row <= lastRow){
                if(column >= firstColumn && column <= lastColumn){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 判断sheet中是否含有合并单元格
     * @param sheet
     * @return
     */
    public static boolean hasMerged(Sheet sheet) {
        return sheet.getNumMergedRegions() > 0 ? true : false ;
    }
}
